package com.taikang.base.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

/**
 * 压缩/解压缩文件工具类
 * @creator     taikang
 * @create-time 2016年4月18日   上午9:32:28
 * @email taikang@taikang.com
 * @company www.taikang.com
 * @version 1.0
 */
public class ZipFileUtil {
	
	private static Log logger = LogFactory.getLog(ZipFileUtil.class);
	
	
	/**
	 * zip压缩功能. 压缩baseDir(文件夹目录)下所有文件，包括子目录
	 * 
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public static void zipFile(String baseDir, String fileName) {
		List fileList = getSubFiles(new File(baseDir));
		ZipOutputStream zos = null;
			
		try {
			zos = new ZipOutputStream(new FileOutputStream(fileName));
			zos.setEncoding("GBK");	//设置为GBK不会乱码了
			ZipEntry ze = null;
			byte[] buf = new byte[1024];
			int readLen = 0;
			for (int i = 0; i < fileList.size(); i++) {
				File f = (File) fileList.get(i);
				ze = new ZipEntry(getAbsFileName(baseDir, f));
				ze.setSize(f.length());
				ze.setTime(f.lastModified());
				zos.putNextEntry(ze);
				InputStream is = new BufferedInputStream(new FileInputStream(f));
				while ((readLen = is.read(buf, 0, 1024)) != -1) {
					zos.write(buf, 0, readLen);
				}
				zos.flush();
				is.close();
			}
		} catch (Exception e) {
			logger.error("",e);
		}finally{
			IOUtils.closeQuietly(zos);
		}
		
	}
	
	/**
	 * 解压缩功能
	 * @param zipFilePath 
	 * @param unzipDirectory
	 * @throws Exception
	 */
	@SuppressWarnings({ "rawtypes" })
	public static void unZipFile(String zipFilePath,String unzipDirectory){
		//多加一级文件夹
		int start = zipFilePath.lastIndexOf(File.separator);
		int end = zipFilePath.lastIndexOf(".");
		String unzipDirName = zipFilePath.substring(start+1,end);
		unzipDirectory = unzipDirectory + unzipDirName + File.separator;
		
		//解压
		ZipFile zfile = null;
		try {
			zfile = new ZipFile(zipFilePath);
			Enumeration zList = zfile.getEntries();
			ZipEntry ze=null;
			byte[] buf=new byte[1024];
			while(zList.hasMoreElements()){
				ze=(ZipEntry)zList.nextElement();	
				if(ze.isDirectory()){
		            File f=new File(unzipDirectory+ze.getName());
		            f.mkdir();
					continue;
				}
				OutputStream os = null;
				InputStream is = null;
				try {
					os = new BufferedOutputStream(new FileOutputStream(getRealFileName(unzipDirectory,ze.getName())));
					is = new BufferedInputStream(zfile.getInputStream(ze));
					int readLen=0;
					while ((readLen=is.read(buf, 0, 1024))!=-1) {
						os.write(buf, 0, readLen);
					}
					os.flush();
				} catch (Exception e) {
					logger.error("",e);
				}finally{
					IOUtils.closeQuietly(is);
					IOUtils.closeQuietly(os);
				}
			}
		} catch (Exception e) {
			logger.error("",e);
		}finally{
			if(null != zfile){
				try {
					zfile.close();
				} catch (Exception e) {
				}
			}
		}
	}
	

	/**
	 * 给定根目录，返回另一个文件名的相对路径，用于zip文件中的路径.
	 * 
	 * @param baseDir
	 *            java.lang.String 根目录
	 * @param realFileName
	 *            java.io.File 实际的文件名
	 * @return 相对文件名
	 */
	private static String getAbsFileName(String baseDir, File realFileName) throws Exception{
		File real = realFileName;
		File base = new File(baseDir);
		logger.debug("realName:" + real.getName());
		String ret = real.getName();
		while (true) {
			real = real.getParentFile();
			if (real == null)
				break;
			if (real.equals(base))
				break;
			else{
				logger.debug("realName:" + real.getName());
				ret = real.getName() + "/" + ret;
			}
				
		}
		return ret;
	}
	
	/**
	* 给定根目录，返回一个相对路径所对应的实际文件名.
	* @param baseDir 指定根目录
	* @param absFileName 相对路径名，来自于ZipEntry中的name
	* @return java.io.File 实际的文件
	*/
	private static File getRealFileName(String baseDir, String absFileName){
		String sep = "/"; 
		if(absFileName.indexOf("/") == -1){
			//没找到/ 说明是\分割
			sep = "\\\\";
		}
		String[] dirs = absFileName.split(sep);
		if(dirs.length > 1){
			for (int i = 0;i < dirs.length - 1 ; i++) {
				baseDir += dirs[i] + File.separator;
			}
		}
		File ret = new File(baseDir);
		if(!ret.exists())
			ret.mkdirs();
		if(dirs.length > 0){
			ret = new File(ret, dirs[dirs.length-1]);
		}
		return ret;
	}
	
	/**
	 * 取得指定目录下的所有文件列表，包括子目录.
	 * 
	 * @param baseDir
	 *            File 指定的目录
	 * @return 包含java.io.File的List
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static List getSubFiles(File baseDir) {
		List ret = new ArrayList();
		File[] tmp = baseDir.listFiles();
		for (int i = 0; i < tmp.length; i++) {
			if (tmp[i].isFile())
				ret.add(tmp[i]);
			if (tmp[i].isDirectory())
				ret.addAll(getSubFiles(tmp[i]));
		}
		return ret;
	}
	
	public static void main(String[] args) {
		ZipFileUtil.unZipFile("D:\\upload.zip", "C:\\");
	}
}
